package com.gkzf.ai.module.crm.util;

import com.gkzf.ai.module.crm.util.extracted.ExtractedMatchContent;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.nodes.TextNode;
import org.jsoup.select.Elements;

import java.io.File;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.gkzf.ai.module.crm.util.AnalysisJsonObjectUtils.*;
import static com.gkzf.ai.module.crm.util.ExcelTemplateParser.verifyIsRepayment;
import static com.gkzf.ai.module.crm.util.HtmlTempkateCommonMethod.*;

@Slf4j
public class HtmlTemplateParser {


    private static final List<String> REPORT_TIME = new ArrayList<>();
    // 自定义表头 本信息人表头
    private static final List<String> LOCALT_INFO = new ArrayList<>();

    // 基本信息表头
    private static final List<String> BASIC_INFO = new ArrayList<>();

    // 循环贷账户
    private static final List<String> REVOLVING_LOAN_ACCOUNT = new ArrayList<>();

    // 贷记卡账户
    private static final List<String> CREDIT_CARD_ACCOUNT = new ArrayList<>();

    // 账户明细
    private static final Map<String, String> ACCOUNT_DETAILS = new LinkedHashMap<>();

    // 账户明细
    private static final Map<String, String> CREDIT_CARD_ACCOUNT_DETAILS = new LinkedHashMap<>();

    // 贷款账户判断表头
    private static List<String> LOAN_TABLE_TITLE ;

    // 信用卡账户判断表头
    private static List<String> CREDIT_CARD_TABLE_TITLE ;

    // 账户状态判断
    private static List<String> ACCOUNT_STATUS_LIST;

    // 担保方式判断
    private static List<String> GUARANTEE_METHOD_LIST;


    static {
        REPORT_TIME.add("报告时间");
        REPORT_TIME.add("报告编号");


        LOCALT_INFO.add("被查询者姓名");
        LOCALT_INFO.add("被查询者证件类型");
        LOCALT_INFO.add("被查询者证件号码");
        LOCALT_INFO.add("查询机构");
        LOCALT_INFO.add("查询原因");
        // 身份信息
        BASIC_INFO.add("性别");
        BASIC_INFO.add("出生日期");
        BASIC_INFO.add("婚姻状况");
        BASIC_INFO.add("就业状况");

        BASIC_INFO.add("学历");
        BASIC_INFO.add("学位");
        BASIC_INFO.add("国籍");
        BASIC_INFO.add("电子邮箱");

        // 非循环贷账户
        REVOLVING_LOAN_ACCOUNT.add("管理机构数");
        REVOLVING_LOAN_ACCOUNT.add("账户数");
        REVOLVING_LOAN_ACCOUNT.add("授信总额");
        REVOLVING_LOAN_ACCOUNT.add("余额");
        REVOLVING_LOAN_ACCOUNT.add("最近6个月平均应还款");
        // 贷记卡
        CREDIT_CARD_ACCOUNT.add("发卡机构数");
        CREDIT_CARD_ACCOUNT.add("账户数");
        CREDIT_CARD_ACCOUNT.add("授信总额");
        CREDIT_CARD_ACCOUNT.add("单家机构最高授信额");
        CREDIT_CARD_ACCOUNT.add("单家机构最低授信额");
        CREDIT_CARD_ACCOUNT.add("已用额度");
        CREDIT_CARD_ACCOUNT.add("最近6个月平均使用额度");

        // 定义需要匹配的表头文本列表
        LOAN_TABLE_TITLE = Arrays.asList(
                "管理机构", "账户标识", "开立日期", "到期日期", "借款金额", "账户币种"
        );
        // 贷款明细
        ACCOUNT_DETAILS.put("管理机构","1");
        ACCOUNT_DETAILS.put("账户标识","1");
        ACCOUNT_DETAILS.put("开立日期","1");
        ACCOUNT_DETAILS.put("到期日期","1");
        ACCOUNT_DETAILS.put("账户授信额度","1");
        ACCOUNT_DETAILS.put("账户币种","1");
        ACCOUNT_DETAILS.put("借款金额","1");


        ACCOUNT_DETAILS.put("业务种类","1");
        ACCOUNT_DETAILS.put("担保方式","1");
        ACCOUNT_DETAILS.put("还款期数","1");
        ACCOUNT_DETAILS.put("还款频率","1");
        ACCOUNT_DETAILS.put("还款方式","1");
        ACCOUNT_DETAILS.put("共同借款标志","1");

        ACCOUNT_DETAILS.put("特殊交易类型","1");
        ACCOUNT_DETAILS.put("发生日期","1");
        ACCOUNT_DETAILS.put("变更月数","1");
        ACCOUNT_DETAILS.put("发生金额","1");
        ACCOUNT_DETAILS.put("明细记录","1");

        ACCOUNT_DETAILS.put("账户状态","1");
        ACCOUNT_DETAILS.put("账户关闭日期","1");
        ACCOUNT_DETAILS.put("五级分类","1");
        ACCOUNT_DETAILS.put("余额","1");
        ACCOUNT_DETAILS.put("剩余还款期数","1");
        ACCOUNT_DETAILS.put("本月应还款","1");
        ACCOUNT_DETAILS.put("应还款日","1");

        ACCOUNT_DETAILS.put("本月实还款","1");
        ACCOUNT_DETAILS.put("最近一次还款日期","1");
        ACCOUNT_DETAILS.put("最迟一次还款日期","1");
        ACCOUNT_DETAILS.put("当前逾期期数","1");
        ACCOUNT_DETAILS.put("当前逾期总额","1");
        ACCOUNT_DETAILS.put("逾期31–60天未还本金","逾.*期.*3.*1.*6.*0.*天.*未.*还.*本.*金");
        ACCOUNT_DETAILS.put("逾期61-90天未还本金","逾.*期.*6.*1.*9.*0.*天.*未.*还.*本.*金");

        ACCOUNT_DETAILS.put("逾期91-180天未还本金","逾.*期.*9.*1.*1.*8.*0.*天.*未.*还.*本.*金");
        ACCOUNT_DETAILS.put("逾期180天以上未还本金","1");
        ACCOUNT_DETAILS.put("还款记录","1");


        CREDIT_CARD_TABLE_TITLE = Arrays.asList(
                "发卡机构", "账户标识", "开立日期", "账户授信额度", "共享授信额度", "币种","业务种类", "担保方式"
        );
        // 贷记卡
        CREDIT_CARD_ACCOUNT_DETAILS.put("发卡机构","1");
        CREDIT_CARD_ACCOUNT_DETAILS.put("账户标识","1");
        CREDIT_CARD_ACCOUNT_DETAILS.put("开立日期","1");
        CREDIT_CARD_ACCOUNT_DETAILS.put("账户授信额度","1");
        CREDIT_CARD_ACCOUNT_DETAILS.put("共享授信额度","1");
        CREDIT_CARD_ACCOUNT_DETAILS.put("币种","1");
        CREDIT_CARD_ACCOUNT_DETAILS.put("业务种类","1");
        CREDIT_CARD_ACCOUNT_DETAILS.put("担保方式","1");
        CREDIT_CARD_ACCOUNT_DETAILS.put("账户状态","1");
        CREDIT_CARD_ACCOUNT_DETAILS.put("余额","1");
        CREDIT_CARD_ACCOUNT_DETAILS.put("已用额度","1");
        CREDIT_CARD_ACCOUNT_DETAILS.put("未出单的大额专项分期余额","1");
        CREDIT_CARD_ACCOUNT_DETAILS.put("剩余分期期数","1");
        CREDIT_CARD_ACCOUNT_DETAILS.put("最近6个月平均使用额度","1");
        CREDIT_CARD_ACCOUNT_DETAILS.put("最大使用额度","1");
        CREDIT_CARD_ACCOUNT_DETAILS.put("账单日","1");
        CREDIT_CARD_ACCOUNT_DETAILS.put("本月应还款","1");
        CREDIT_CARD_ACCOUNT_DETAILS.put("本月实还款","1");
        CREDIT_CARD_ACCOUNT_DETAILS.put("最近一次还款日期","1");
        CREDIT_CARD_ACCOUNT_DETAILS.put("当前逾期期数","1");
        CREDIT_CARD_ACCOUNT_DETAILS.put("当前逾期总额","1");
        CREDIT_CARD_ACCOUNT_DETAILS.put("销户日期","1");

        CREDIT_CARD_ACCOUNT_DETAILS.put("大额专项分期额度","1");
        CREDIT_CARD_ACCOUNT_DETAILS.put("分期额度生效日期","1");
        CREDIT_CARD_ACCOUNT_DETAILS.put("分期额度到期日期","1");
        CREDIT_CARD_ACCOUNT_DETAILS.put("已用分期金额","1");

        // 账户状态所有值
        ACCOUNT_STATUS_LIST = Arrays.asList(
                "正常", "逾期", "结清", "呆账", "催收", "冻结","止付", "关闭","注销","转出","转移","转出/转移","代偿"
        );
        // 担保方式
        GUARANTEE_METHOD_LIST = Arrays.asList(
                "抵押", "质押", "保证", "信用/无担保", "组合担保", "其他");
        // "正常");如果有不在这个表格中的固定信息，需要单独处理或定义不同的映射方式
    }


    /**
     * 判断 开立日期 是否是有效日期
     */
    // 定义日期格式的 Pattern
        private static final String DATE_PATTERN = "yyyy.MM.dd";
        // 创建一个 DateTimeFormatter 实例，它是线程安全的
        private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern(DATE_PATTERN);

        /**
         * 判断给定的字符串是否是 yyyy.MM.dd 格式的有效日期
         * @param dateString 要检查的字符串
         * @return 如果字符串符合格式并且是一个有效的日期，则返回 true；否则返回 false
         */
        public static boolean isValidDateFormat(String dateString) {
            if (dateString == null) {
                return false; // 处理 null 输入
            }
            try {
                // 尝试使用定义的格式解析字符串为 LocalDate 对象
                // 如果解析成功，说明格式是正确的，并且日期是有效的（例如，它不会接受 2023.13.40）
                LocalDate.parse(dateString, DATE_FORMATTER);
                return true;
            } catch (DateTimeParseException e) {
                // 如果解析失败，会抛出 DateTimeParseException，说明字符串不符合指定的格式或日期无效
                // 可以选择打印日志 e.getMessage() 查看具体失败原因
                // System.err.println("Failed to parse date string: " + dateString + " - " + e.getMessage()); // Optional: log error
                return false;
            }
        }


    // 定义正则表达式 Pattern。^表示字符串开头，\d表示任意数字，+表示一个或多个， $表示字符串结尾
    private static final Pattern PURE_NUMERIC_PATTERN = Pattern.compile("^\\d+$");

    /**
     * 判断余额是否是纯数字
     * 判断字符串是否只包含纯数字 (0-9) 使用正则表达式
     * @param number 要检查的字符串
     * @return 如果字符串非空且只包含一个或多个数字，则返回 true；否则返回 false
     */
    public static boolean isPurelyNumericRegex(String number) {
        // 检查 null。str.matches() 如果 str 是 null 会抛 NullPointerException
        if (number == null) {
            return false;
        }
        // 使用 matches() 方法判断整个字符串是否与正则表达式匹配
        // "^\\d+$" 匹配从头到尾（^...$）包含一个或多个（+）数字（\d）的字符串
        return PURE_NUMERIC_PATTERN.matcher(number).matches();
        // 或者更简洁地写： return str.matches("^\\d+$");
    }

    /**
     *  计算还款记录
     * @param table
     * @return
     */
    public static Map<String, YearlyRecord> readRepaymentRecord(String table){

        ExtractedMatchContent extractedMatchContent = new ExtractedMatchContent();
        Map<String, YearlyRecord> stringYearlyRecordMap = extractedMatchContent.parseTables(table);
        log.info(stringYearlyRecordMap.toString());
        return stringYearlyRecordMap;
    }

    public static void extractSEMICOLON(List<String> keyList,List<String> valueList,Element tdElement,Map<String, String> titleMap,AtomicInteger index,String singleLineString,String chinese) {
        if (singleLineString.contains(chinese)) {
            String[] split = singleLineString.split(chinese);
            if (split.length == 2 && Objects.nonNull(matchKey(titleMap, split[0]))){
                keyList.add(split[0]);
                valueList.add(index + "_" + split[1].replace(" ",""));
                index.incrementAndGet();
            }
        }
    }


    private static final String SEMICOLON_CHINESE = "：";

    private static final String SEMICOLON_ENGLISH = "：";
    public static void getLoanAccountDetails(List<String> keyList,List<String> valueList, Element tdElement, Map<String, String> titleMap,AtomicInteger index) {
        if (StringUtils.isNotBlank(tdElement.text())) {

            if (Objects.nonNull(matchKey(titleMap, tdElement.text().replace("<br>\n", "")))) {
                keyList.add(tdElement.text().replace("<br>\n", ""));
            } else {
                Document doc = Jsoup.parseBodyFragment(tdElement.text().replace("<br>\n", ""));

                // 使用 text() 方法获取纯文本内容
                // Jsoup 的 text() 会移除所有标签，并且通常会合并多个空白字符为一个空格
                String singleLineString = doc.body().text().replace("<br>\n", "");
                extractSEMICOLON(keyList, valueList, tdElement, titleMap, index, singleLineString,SEMICOLON_CHINESE);
                extractSEMICOLON(keyList, valueList, tdElement, titleMap, index, singleLineString,SEMICOLON_ENGLISH);
                valueList.add(index + "_" + singleLineString.replace(" ",""));
                index.incrementAndGet();
            }
        }
    }


    public static void getCreditCardAccountDetails(List<String> keyList,List<String> valueList, Element tdElement,Map<String, String> titleMap,AtomicInteger index) {
        if (StringUtils.isNotBlank(tdElement.text())) {
            Document doc = Jsoup.parseBodyFragment(tdElement.html());
            // 获取<td>元素，因为内容在它里面
            Element body = doc.body();
            String title = "";
            String value = "";
            boolean foundBr = false; // 标记是否已经遇到了 <br>

            // 遍历<td>的所有子节点
            for (Node node : body.childNodes()) {
                // 如果是 <br> 标签
                if (node.nodeName().equals("br")) {
                    foundBr = true; // 标记已找到 <br>
                    continue; // 跳过 <br> 节点本身
                }
                // 如果是文本节点
                if (node instanceof TextNode textNode) {
                    String text = textNode.text(); // 获取文本内容

                    if (!foundBr) {
                        // <br> 之前的文本
                        title += text;
                    } else {
                        // <br> 之后的文本
                        value += text;
                    }
                    // 可以选择忽略其他类型的节点（如嵌套的子元素，如果存在的话）
                }
            }
            if (!titleMap.containsKey(title)) {
                getLoanAccountDetails(keyList, valueList, tdElement, titleMap, index);
                return;
            }
            keyList.add(title);
            valueList.add(index + "_" + value);
            index.incrementAndGet();
        }
    }


    /**
     * 将组装的一个账户信息 来 拼凑 组装 判断转换成一个map
     * @param accountList 账户信息集合
     * @param loanDetails 贷款明细List
     * @param titleMap 标题映射
     * @param accountArray 账户信息
     * @param account 账户信息
     * @param entry 账户信息详情
     */
    public static void extractAccountInformation(List<Map<String,Object>> accountList,
                                                 List<Element> loanDetails,
                                                 Map<String, String> titleMap,
                                                 String[] accountArray,
                                                 String[] account,
                                                 Map.Entry<String,Element> entry){
                       /*
                 如果是一个账户2个 table 如果标题和值分开不容易 寻找 所有如果是一个table 就把2个table 合并成 一个table
                 */
        if (!loanDetails.isEmpty()){
            Element loanDetail = mergeTables(loanDetails);
            account[0] = accountArray[0];
            List<String> keyList = new ArrayList<>();
            List<String> valueList = new ArrayList<>();
            // 区分贷记value值下标 因为有些值会重复
            AtomicInteger index = new AtomicInteger(0);
            // 判断是否还款记录 出现则停止循环 table
            AtomicBoolean repaymentStopped = new AtomicBoolean(true);
            StringBuilder allRowsHtml = new StringBuilder("<table>\n");

            // 账户明细  读取 tr td 不判断带有截至的字符的td(这个是单行的td 用处)
            if (!verifyIsRepayment(loanDetail)) {
                List<Element> elementList = loanDetail.select("tr")
                        .stream().toList().stream().filter(item ->!item.text().contains("截") && !item.text().contains("授信协议标识")).toList();
                           /*

                              判断 td 是否我配置的 key 如果是进入 keyList 否则进入 valueList
                              判断格式是 一个 tr 一个 tr 判断 判断下一个tr 是不是 还款记录
                              还款记录 可能 在大table 也可以 在 另一个table嘛
                            */


                for (Element tr : elementList) {

                    Elements td = tr.select("td");
                    boolean isMatchSuccessful = checkTableCells(td);
                    if (isMatchSuccessful) {
                        repaymentStopped.set(false);
                    }
                             /*
                                  判断 是否是 还款记录
                                  一行一行 判断 还款记录是否夹在 table 中
                                 */
                    if (!repaymentStopped.get()) {
                        if (verifyTrsContainNoChinese(tr)) {
                            allRowsHtml.append(tr.outerHtml() + "\n");
                        }
                        continue;
                    }
                    for (Element tdElement : td) {
                        boolean isRepayment = containsYearMonthRepaymentRecordPattern(tdElement.text());
                        if (isRepayment) {
                            repaymentStopped.set(false);
                            continue;
                        }
//                        if (td.html().contains("<br>")) {

                                    /*
                                      <tr>
                                        <td>发卡机构<br>名称变更为中国建设银行股份有限公司南京建邺支行</td>
                                        <td>账户标识<br>B10411000H000115602800002121682822615402</td>
                                        <td>开立日期<br>2020.07.30</td><td>账户授信额度<br>57,000</td>
                                        <td>共享授信额度<br>--</td>
                                        <td>币种<br>人民币元</td>
                                        <td>业务种类<br>贷记卡</td>
                                        <td>担保方式<br>信用/无担保</td>
                                      </tr>
                                      下面写法解析这样结构的
                                     */

//                            getCreditCardAccountDetails(keyList, valueList, tdElement, titleMap, index);
//                        } else {
                                    /*
                                        <tr>
                                            <td>账户状态</td>
                                            <td>五级分类</td>
                                            <td>余额</td>
                                            <td>剩余还款期数</td>
                                            <td>本月应还款</td>
                                            <td>应还款日</td>
                                            <td>本月实还款</td>
                                            <td>最近一次还款日期</td>
                                          </tr>
                                          <tr>
                                            <td>正常</td>
                                            <td>正常</td>
                                            <td>146,932</td>
                                            <td>36</td>
                                            <td>1,313</td>
                                            <td>2024.12.21</td>
                                            <td>1,313</td>
                                            <td>2024.12.21</td>
                                          </tr>

                                          下面写法解析这样结构的
                                     */
                            getLoanAccountDetails(keyList, valueList, tdElement, titleMap, index);
//                        }
                    }
                }
            } else {
                List<Element> elementList = loanDetail.select("tr")
                        .stream()
                        .filter(item -> !item.text().contains("截至")).toList();
                for (Element tr : elementList) {
                    if (verifyTrsContainNoChinese(tr)) {
                        allRowsHtml.append(tr.outerHtml() + "\n");
                    }
                }

            }
            allRowsHtml.append("\n</table>");
            Map<String, YearlyRecord> stringYearlyRecordMap = readRepaymentRecord(allRowsHtml.toString());
            Map<String, Object> accountDetailMap = new HashMap<>();

            log.info("账户:{}",account[0]);
            for (int i = 0; i < keyList.size(); i++) {
                String value = "";
                if (i < valueList.size()){
                    try {
                        value = valueList.get(i).split("_")[1];
                    }catch (ArrayIndexOutOfBoundsException e){
                        value = "";
                    }
                }
                accountDetailMap.put(keyList.get(i),value);
            }

                /*
                  有些也是纯数字的td 会出现在 还款记录下面  删除掉 年 key 不符合 key的集合
                 */
            if (!stringYearlyRecordMap.isEmpty()){
                Iterator<Map.Entry<String, YearlyRecord>> iterator = stringYearlyRecordMap.entrySet().iterator();
                while (iterator.hasNext()) {
                    Map.Entry<String, YearlyRecord> next = iterator.next();
                    if (!YEAR_PATTERN.matcher(next.getKey()).find()){
                        iterator.remove();
                    }
                }
            }
            accountDetailMap.put("还款记录",stringYearlyRecordMap);
            accountList.add(accountDetailMap);
            loanDetails.clear();
            // 加上另一个账户的第一行
            // 最后一行 不需要添加
            if (null != entry) {
                loanDetails.add(entry.getValue());
            }
        }

    }

    /**
     * 解析贷款明细
     * @param accountList
     * @param elementMap
     * @param titleMap
     */
    public static void readAccountInfoDetails(List<Map<String,Object>> accountList,Map<String,Element> elementMap,Map<String, String> titleMap){
        // 解析 贷款明细
        List<Element> loanDetails = new ArrayList<>();

        final String[] account = {"1"};

        elementMap.entrySet().forEach(entry -> {
            /*
               账户明细 我只区分 贷款和信用卡 贷款分3种类型 里面的账户1会重复 所有不好做判断 只能前缀使用随机数字区分
             */
            String key = entry.getKey();
            String[] accountArray = key.split("_");
            // 当判断不等于时 说明是新的账户  但是会把另一个账户第一行给判断掉了 等于第一行都不会加
            if (accountArray[0].contains(account[0])){
                loanDetails.add(entry.getValue());
            }else {
                extractAccountInformation(accountList, loanDetails, titleMap,accountArray, account,entry);
            }
        });
        if (!loanDetails.isEmpty()){
            extractAccountInformation(accountList, loanDetails, titleMap, new String[]{""}, new String[]{""},null);
        }
    }


    public static List<Map<String,String>> extractQueryDetails(List<Element> elementList) {
        List<Map<String,String>> list = new ArrayList<>();
        elementList.forEach(entry ->{
            entry.select("tr").forEach(tr -> {
                if (hasNonAllowedTdValue(tr)){
                    log.info(tr.html());

                    Boolean isDate = true;
                    Map<String, String> queryMap = new LinkedHashMap<>();
                    Elements tds = tr.select("td");
                    queryMap.put("编号", "--");
                    queryMap.put("查询日期", "--");
                    queryMap.put("查询机构", "--");
                    queryMap.put("查询原因", "--");
                    if (!tds.isEmpty())
                        if (tds.stream().anyMatch(item -> !item.text().contains("页"))) {
                        queryMap.put("编号", tds.get(0).text());
                        if (tds.size() > 1) {
                            if (!isValidDateFormat(tds.get(1).text())) {
                                isDate = false;
                            }
                            queryMap.put("查询日期", tds.get(1).text());
                        }
                        if (tds.size() > 2) {
                            queryMap.put("查询机构", tds.get(2).text());
                        }
                        if (tds.size() > 3) {
                            queryMap.put("查询原因", tds.get(3).text());
                        }
                        if (isDate) {
                            list.add(queryMap);
                        }
                    }
                }
            });
        });
        return list;
    }

    public static void main(String[] args) {
        File file = new File("/Users/mac/Downloads/138fa307-1a8c-424b-807e-986c58ae666d.html");
        Map<String, Object> map = analysisCreditCreport(file);
        log.info(map.toString());
    }


    @SneakyThrows
    public static Map<String,Object> analysisCreditCreport(File inputFile) {
        // 读取 HTML 文件
        Document document = Jsoup.parse(inputFile, "UTF-8");
        Map<String,Object> finallyMap = new HashMap<>();
        try {
            AtomicBoolean atomicInteger = new AtomicBoolean(true);
            // 使用 CSS 选择器查找元素
            Elements tables = document.select("table");
            // 查找第一个 <a> 标签
            for (Element table : tables) {
                List<Map<String, String>> reportTimeInfoList = parseBasicFlexibleTable(table, REPORT_TIME);
                if (!reportTimeInfoList.isEmpty()){
                    List<Map<String, String>> collect = reportTimeInfoList.stream().filter(entry -> entry.get("报告时间") != null)
                            .collect(Collectors.toList());
                    if (!collect.isEmpty()){
                        finallyMap.put("报告时间",collect.get(0).get("报告时间"));
                    }

                }


                    List<Map<String, String>> localtInfoList = parseBasicFlexibleTable(table, LOCALT_INFO);
                    if (!localtInfoList.isEmpty() && atomicInteger.get()){
                        finallyMap.put("本人信息", localtInfoList);
                        atomicInteger.set(false);
                    }

//                if (atomicInteger.get() == 1) {
//                    List<Map<String, String>> list = parseFlexibleTable(table, BASIC_INFO);
//                    if (!list.isEmpty()){
//                        atomicInteger.incrementAndGet();
//                        finallyMap.put("身份信息", list);
//                    }
//                }
            }

            String nonSelector = "h1:contains(非循环贷账户信息汇总) + table";
            Element nonTargetTable = document.selectFirst(nonSelector);
            if (nonTargetTable != null) {
                List<Map<String, String>> revolvingLoanAccountOneList = parseFlexibleTable(nonTargetTable, REVOLVING_LOAN_ACCOUNT);
                if (!revolvingLoanAccountOneList.isEmpty()) {
                    finallyMap.put("非循环贷账户信息汇总", revolvingLoanAccountOneList);
                }
            }


            String oneSelector = "h1:contains(循环贷账户一信息汇总) + table";
            Element oneTargetTable = document.selectFirst(oneSelector);
            if (oneTargetTable != null) {
                List<Map<String, String>> revolvingLoanAccountOneList = parseFlexibleTable(oneTargetTable, REVOLVING_LOAN_ACCOUNT);
                if (!revolvingLoanAccountOneList.isEmpty()) {
                    finallyMap.put("循环贷账户一信息汇总", revolvingLoanAccountOneList);
                }
            }

            String towSelector = "h1:contains(循环贷账户二信息汇总) + table";
            Element towTargetTable = document.selectFirst(towSelector);
            if (towTargetTable != null) {
                List<Map<String, String>> revolvingLoanAccountOneList = parseFlexibleTable(towTargetTable, REVOLVING_LOAN_ACCOUNT);
                if (!revolvingLoanAccountOneList.isEmpty()) {
                    finallyMap.put("循环贷账户二信息汇总", revolvingLoanAccountOneList);
                }
            }

            String creditCardSelector = "h1:contains(贷记卡账户信息汇总) + table";
            Element creditCardTargetTable = document.selectFirst( creditCardSelector);
            if (creditCardTargetTable != null) {
                List<Map<String, String>> revolvingLoanAccountOneList = parseFlexibleTable(creditCardTargetTable, CREDIT_CARD_ACCOUNT);
                if (!revolvingLoanAccountOneList.isEmpty()) {
                    finallyMap.put("贷记卡账户信息汇总", revolvingLoanAccountOneList);
                }
            }



            // 贷款起始位置
            // 定义要查找的文本模式，按优先级排序
            List<String> loanTextPatterns = Arrays.asList(
                    ".*([一]).*非循环贷账户.*",
                    ".*([一二]).*循环贷账户一.*",
                    ".*([一二三]).*循环贷账户二.*"
            );
            Element loanAccountHeading = findLoanAccountHeading(document, loanTextPatterns);


            // 贷款卡起始位置
            // 定义要查找的文本模式，按优先级排序
            List<String> creditCardTextPatterns = Arrays.asList(
                    ".*([一二三四]).*贷记卡账户.*"
            );

            Element creditCardAccountHeading = findLoanAccountHeading(document, creditCardTextPatterns);

            // 贷款/信用卡结束位置
            // 定义要查找的文本模式，按优先级排序
            List<String> fourEndTextPatterns = Arrays.asList(
                    ".*([一二三四五]).*(授信协议信息|相关还款责任信息).*"
            );
            Element afourEndAccountHeading = findLoanAccountHeading(document, fourEndTextPatterns);


            // 贷款/信用卡结束位置
            // 定义要查找的文本模式，按优先级排序
            List<String> queryDetailsStartTextPatterns = Arrays.asList(
                    ".*查询记录明细.*"
            );
            Element queryDetailsStartHeading = findLoanAccountHeading(document, queryDetailsStartTextPatterns);

            // 贷款/信用卡结束位置
            // 定义要查找的文本模式，按优先级排序
            List<String> queryDetailsEndTextPatterns = Arrays.asList(
                    ".*报告说明.*"
            );

            Element queryDetailstEndHeading = findLoanAccountHeading(document, queryDetailsEndTextPatterns);


            AtomicInteger prefix = new AtomicInteger(1);
            Map<String, Element> loanElementMap = new LinkedHashMap<>();
            // 贷款 table 获取
            Element endElement = creditCardAccountHeading;
            /*
             如果 贷记卡不存在 则征信报告不存在 四 贷记卡 去寻找四
             */
            if (loanAccountHeading != null) {
                log.info("贷款账户开始位置: " + loanAccountHeading.text());
                if (endElement == null) {
                    endElement = afourEndAccountHeading;
                }
                if (endElement != null) {
                    extractLoanTablesBetween(loanAccountHeading, endElement, loanElementMap,prefix,LOAN_TABLE_TITLE);
                }
            }

            Map<String,Element> creditCardAccountElementMap = new LinkedHashMap<>();
            // 信用卡 table 获取
            if (creditCardAccountHeading != null) {
                log.info("信用卡账户开始位置: " + creditCardAccountHeading.text());
                endElement = afourEndAccountHeading;
                if (endElement != null) {
                    prefix.set(1);
                    extractLoanTablesBetween(creditCardAccountHeading, endElement, creditCardAccountElementMap,prefix,CREDIT_CARD_TABLE_TITLE);
                }
            }

            List<Element> queryRecordDetailsList = new ArrayList<>();
            // 信用卡 table 获取
            if (queryDetailsStartHeading != null) {
                log.info("贷款查询明细开始位置: " + queryDetailsStartHeading.text());
                endElement = queryDetailstEndHeading;
                if (endElement != null) {
                    extractQueryDetailsTablesBetween(queryDetailsStartHeading, endElement, queryRecordDetailsList);
                }
            }


            // 非循环贷
            List<Map<String,Object>> nonRevolvingLoanAccountList = new ArrayList<>();
//            readAccountInfoDetails(nonRevolvingLoanAccountList,loanElementMap,ACCOUNT_DETAILS);
            ListIterator<Map<String, Object>> loanIterator = nonRevolvingLoanAccountList.listIterator();
            while (loanIterator.hasNext()) {
                AtomicInteger isAccountNormal = new AtomicInteger(0);
                Map<String, Object> next = loanIterator.next();
                // 判断账户状态
                if (next.containsKey(ACCOUNT_STATUS)){
                    if (!ACCOUNT_STATUS_LIST.contains(next.get(ACCOUNT_STATUS).toString())){
                        isAccountNormal.incrementAndGet();
                    }
                }else {
                    isAccountNormal.incrementAndGet();
                }
                // 判断担保方式
                if (next.containsKey(GUARANTY_STYLE)){
                    if (!GUARANTEE_METHOD_LIST.contains(next.get(GUARANTY_STYLE).toString())){
                        isAccountNormal.incrementAndGet();
                    }
                }else{
                    isAccountNormal.incrementAndGet();
                }
                // 判断借款金额
                if (next.containsKey(LOAN_AMOUNT)){
                    if ((!isPurelyNumericRegex(next.get(LOAN_AMOUNT).toString().replace(",","")))){
                        isAccountNormal.incrementAndGet();
                    }
                }else{
                    isAccountNormal.incrementAndGet();
                }

                // 还款期数
                if (next.containsKey(REPAYMENT_PERIOD)){
                    if ((!isPurelyNumericRegex(next.get(REPAYMENT_PERIOD).toString().replace(",","")))){
                        isAccountNormal.incrementAndGet();
                    }
                }else{
                    isAccountNormal.incrementAndGet();
                }

                // 判断开立日期
                if (next.containsKey(OPENING_DATE)){
                    if ((!isValidDateFormat(next.get(OPENING_DATE).toString()))){
                        isAccountNormal.incrementAndGet();
                    }
                }else{
                    isAccountNormal.incrementAndGet();
                }
                if (isAccountNormal.get() > 0){
                    loanIterator.remove();
                }

            }
//            finallyMap.put("贷款",nonRevolvingLoanAccountList);
            // 贷记卡账户
            List<Map<String,Object>> creditCardAccountList = new ArrayList<>();
//            readAccountInfoDetails(creditCardAccountList,creditCardAccountElementMap,CREDIT_CARD_ACCOUNT_DETAILS);
//            finallyMap.put("贷记卡账户",creditCardAccountList);
            ListIterator<Map<String, Object>> creditCardIterator = creditCardAccountList.listIterator();
            while (creditCardIterator.hasNext()) {
                AtomicInteger isAccountNormal = new AtomicInteger(0);
                Map<String, Object> next = creditCardIterator.next();
                // 判断账户状态
                if (next.containsKey(ACCOUNT_STATUS)){
                    if (!ACCOUNT_STATUS_LIST.contains(next.get(ACCOUNT_STATUS).toString())){
                        isAccountNormal.incrementAndGet();
                    }
                }else {
                    isAccountNormal.incrementAndGet();
                }
                // 判断担保方式
                if (next.containsKey(GUARANTY_STYLE)){
                    if (!GUARANTEE_METHOD_LIST.contains(next.get(GUARANTY_STYLE).toString())){
                        isAccountNormal.incrementAndGet();
                    }
                }else{
                    isAccountNormal.incrementAndGet();
                }

                // 业务种类
                if (next.containsKey(BUSINESS_TYPE)){
                    if (!Objects.equals(next.get(BUSINESS_TYPE).toString(),CREDIT_CARD)){
                        isAccountNormal.incrementAndGet();
                    }
                }else{
                    isAccountNormal.incrementAndGet();
                }

                // 判断开立日期
                if (next.containsKey(OPENING_DATE)){
                    if ((!isValidDateFormat(next.get(OPENING_DATE).toString()))){
                        isAccountNormal.incrementAndGet();
                    }
                }else{
                    isAccountNormal.incrementAndGet();
                }
                if (isAccountNormal.get() > 0){
                    creditCardIterator.remove();
                }

            }

            // 查询记录

            List<Map<String, String>> list = extractQueryDetails(queryRecordDetailsList);
            finallyMap.put("查询记录",list);
            log.info("最终结果：{}", finallyMap);

            return finallyMap;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
